<?php
declare (strict_types=1);

namespace wechat;

use app\admin\model\advertiser\AdvertiserMatter;
use app\admin\model\base\User;
use app\admin\model\base\UserOfficial;
use app\admin\model\base\UserSubscribeLog;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\RuntimeException;
use EasyWeChat\Kernel\Messages\News;
use EasyWeChat\Kernel\Messages\Text;
use EasyWeChat\Kernel\Messages\NewsItem;
use EasyWeChat\OpenPlatform\Server\Guard;
use Symfony\Component\HttpFoundation\Response;
use think\facade\Cache;
use think\facade\Log;
use function Symfony\Component\HttpFoundation\Session\Storage\Proxy\write;

/**
 * 无塑地球主体微信开放平台
 */
class WsOpenPlatform
{
    //微信开放平台
    public object $openPlatform;
    public string $name;
    public string $appid;
    public string $secret;
    public string $qrcode;
    public string $token;
    public string $aes_key;
    //重定向地址
    public string $redirect_uri;
    //回复消息模板
    public array $newsTemplate = [];

    /**
     * 初始化
     */
    public function __construct()
    {
        //获取重定向地址
        $this->redirect_uri = env('ApiDomainV2') . '/scan_bag/wechatJump';
        //回复消息模板
        $this->newsTemplate = [
            'title' => '点我进入领袋流程',
            'description' => '公益环保，为爱蓄力',
            'url' => $this->redirect_uri,
            'image' => env('ApiDomainV2') . '/static/logo/logo.png',
        ];
        //获取系统配置
        $sys_config = config('sys_config.WsOpenPlatform');
        $this->name = $sys_config['name'];
        $this->appid = $sys_config['appid'];
        $this->secret = $sys_config['secret'];
        $this->token = $sys_config['token'];
        $this->aes_key = $sys_config['aes_key'];
        $config = [
            'app_id' => $this->appid,
            'secret' => $this->secret,
            'token' => $this->token,
            'aes_key' => $this->aes_key,
            'response_type' => 'array',
        ];
        $this->openPlatform = Factory::openPlatform($config);
        //替换应用中的缓存
        $this->openPlatform->rebind('cache', app()->cache);
    }

    /**
     * 处理授权VerifyTicket
     * @return Response
     */
    public function verifyTicket(): Response
    {
        $server = $this->openPlatform->server;
        //处理授权成功事件
        $server->push(function ($message) {
            switch ($message['InfoType']) {
                case 'authorized'://授权成功
                    break;
                default:
                    break;
            }
        }, Guard::EVENT_AUTHORIZED);

        //处理授权更新事件
        $server->push(function ($message) {
            switch ($message['InfoType']) {
                case 'updateauthorized'://授权成功
                    break;
                default:
                    break;
            }
        }, Guard::EVENT_UPDATE_AUTHORIZED);

        //处理授权取消事件
        $server->push(function ($message) {
            //更新数据库
            $where = ['appid' => $message['AuthorizerAppid']];
            $data = ['auth' => 0, 'auth_info' => json_encode([]), 'auth_time' => 0];
            AdvertiserMatter::update($data, $where);
        }, Guard::EVENT_UNAUTHORIZED);

        return $server->serve()->send();
    }

    /**
     * 处理自定义消息处理器
     * @param string $appid
     * @return Response
     */
    public function dealWithPushMsg(string $appid): Response
    {
        //微信公众号服务
        //获取当前公众号的$refreshToken
        $info = $this->getAuthorizer($appid);
        Log::write($info);
        $refreshToken = $info['authorization_info']['authorizer_refresh_token'];
        $app_name = $info['authorizer_info']['nick_name']??'';
        $officialAccount = $this->openPlatform->officialAccount($appid,$refreshToken);
        //这里的server为授权方的server，而不是开放平台的server，请注意！！！
        $server = $officialAccount->server;
        $server->push(function ($message) use ($appid,$officialAccount,$app_name) {
            //定义取袋图文消息
            $NewsItem = [
                new NewsItem($this->newsTemplate),
            ];

            Log::write(json_encode($message));

            Log::write($appid);
            //判断消息类型
            switch ($message['MsgType']) {
                case 'event':
                    //扫码取袋回复
                    if ($message['Event'] == 'SCAN' and $message['EventKey'] == 'scan_bag') {
                        //写入用户关注 todo
                        $officialAccount->customer_service->message(new Text("您好，欢迎关注".$app_name))->to($message['FromUserName'])->send();
                        return new News($NewsItem);
                    }
                    //扫码关注取袋回复
                    if ($message['Event'] == 'subscribe' and $message['EventKey'] == 'qrscene_scan_bag') {
                        //写入用户关注 todo
                        $user_info =$officialAccount->user->get($message['FromUserName']);
                        Log::write(json_encode($user_info));
                        //
                        if(isset($user_info['unionid'])){
                            $where1 =['unionid'=>$user_info['unionid']];
                            $user = User::findOne($where1);
                            if($user){
                                Log::write('111');
                                //更新关注情况
                                $where2 =['user_id' => $user['id'], 'appid' => $appid];
                                $user_offical =UserOfficial::where($where2)->find();
                                if($user_offical){
                                    Log::write('222');
                                    $user_offical->subscribe=1;
                                    $user_offical->openid=$user_info['openid'];
                                    $user_offical->save();
                                    UserSubscribeLog::oneLogSave($user['id'],$appid,1,$user_info['openid']);
                                }
                            }else{
                                Log::write('333');
                                UserSubscribeLog::oneLogSave(0,$appid,1,$user_info['openid']);
                            }
                        }else{
                            Log::write('444');
                            UserSubscribeLog::oneLogSave(0,$appid,1,$user_info['openid']);
                        }
                        $officialAccount->customer_service->message(new Text("您好，欢迎关注".$app_name))->to($message['FromUserName'])->send();
                        return new News($NewsItem);
                    }
                    //用户关注回复
                    if ($message['Event'] == 'unsubscribe') {
                        $user_info =$officialAccount->user->get($message['FromUserName']);
                        Log::write($user_info);
                        //
                        //更新关注情况
                        $where2 =['openid' => $user_info['openid'], 'appid' => $appid];
                        $user_offical =UserOfficial::where($where2)->find();
                        if($user_offical){
                            $user_offical->subscribe=0;
                            $user_offical->openid=$user_info['openid'];
                            $user_offical->save();
                            UserSubscribeLog::oneLogSave($user_offical['user_id'],$appid,0,$user_info['openid']);
                        }else{
                            UserSubscribeLog::oneLogSave(0,$appid,0,$user_info['openid']);
                        }
                        return new News($NewsItem);
                    }
                    break;
                case 'text':
                    //回复176返回取袋链接
                    if ($message['Content'] == '176') {
                        $officialAccount->customer_service->message(new Text("您好，欢迎关注".$app_name))->to($message['FromUserName'])->send();
                        return new News($NewsItem);
                    }
                    break;
                case 'image':
                case 'voice':
                case 'video':
                case 'location':
                case 'link':
                case 'file':
                $officialAccount->customer_service->message(new Text("您好，欢迎关注".$app_name))->to($message['FromUserName'])->send();
                    return new News($NewsItem);
            }
            $officialAccount->customer_service->message(new Text("您好，欢迎关注".$app_name))->to($message['FromUserName'])->send();
            return new News($NewsItem);
        });

        return $server->serve()->send();
    }

    /**
     * 获取用户授权页URL
     * @param string $redirect_uri
     * @return string
     */
    public function getPreAuthorizationUrl(string $redirect_uri): string
    {
        try {
            return $this->openPlatform->getPreAuthorizationUrl($redirect_uri);
        } catch (RuntimeException $e) {
            return $e->getMessage();
        }
    }

    /**
     * 使用授权码换取接口调用凭据和授权信息
     * @return mixed
     */
    public function handleAuthorize(): mixed
    {
        return $this->openPlatform->handleAuthorize();
    }

    /**
     * 获取授权方账号基本信息
     * @param string $appId
     * @return mixed
     */
    public function getAuthorizer(string $appId): mixed
    {
        return $this->openPlatform->getAuthorizer($appId);
    }

    /**
     * 获取已授权的授权方列表
     * @param int $offset
     * @param int $count
     * @return mixed
     */
    public function getAuthorizers(int $offset = 0, int $count = 500): mixed
    {
        return $this->openPlatform->getAuthorizers($offset, $count);
    }

    /**
     * 获取公众号带参数的二维码url
     * @param string $appId
     * @param string $sceneValue
     * @return string
     */
    public function officialAccountTemporaryQrcode(string $appId, string $sceneValue): string
    {
        $tKey = $appId . '_temporary_qrcode:' . $sceneValue;
        //判断是否存在缓存
        if (Cache::has($tKey)) {
            $temp = Cache::get($tKey);
        } else {
            //获取当前公众号的$refreshToken
            $info = $this->getAuthorizer($appId);
            $refreshToken = $info['authorization_info']['authorizer_refresh_token'];
            //代公众号
            $officialAccount = $this->openPlatform->officialAccount($appId, $refreshToken);
            $temp = $officialAccount->qrcode->temporary($sceneValue, 1300000);
            //存入redis
            Cache::set($tKey, $temp, 1296000);
        }
        return $temp['url'];
    }

    //代小程序实现业务
    public function miniProgram(string $appId, string $refreshToken)
    {
        $miniProgram = $this->openPlatform->miniProgram($appId, $refreshToken);
        $account = $miniProgram->account;

        halt($miniProgram);
    }

}















